package org.yyf.resource.intercepter;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;

//@Intercepts({ @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
//		RowBounds.class, ResultHandler.class }) })

@Intercepts({
		@Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
@Component
public class MybatisInterceptor implements Interceptor {

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		// 获取原始sql语句 拦截Executor.class 方式。。 修改sql比较繁琐 不推荐
//		MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
//		Object parameter = invocation.getArgs()[1];
//		BoundSql boundSql = mappedStatement.getBoundSql(parameter);
//		String sql = boundSql.getSql();
//		System.out.println(sql);
		

		// 获取原始sql语句
		StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
		MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY,
				SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
		// 先拦截到RoutingStatementHandler，里面有个StatementHandler类型的delegate变量，其实现类是BaseStatementHandler，然后就到BaseStatementHandler的成员变量mappedStatement
		MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");

		// 执行的mapper方法的全路径名，org.yyf.resource.demo.mybatis.mapper.UserMapper.get
		String methodFullName = mappedStatement.getId();
		System.out.println("调用方法全类名：" + methodFullName);

		// sql语句类型 select、delete、insert、update
		String sqlType = mappedStatement.getSqlCommandType().toString();
		System.out.println("sql语句类型:" + sqlType);

		BoundSql boundSql = statementHandler.getBoundSql();

		// 获取到原始sql语句
		String sql = boundSql.getSql();
		System.out.println("原始sql:" + sql);

		// 仅添加SqlChange注解生效
		Class<?> classType = Class
				.forName(methodFullName.substring(0, mappedStatement.getId().lastIndexOf(".")));
		String methodName = methodFullName.substring(mappedStatement.getId().lastIndexOf(".") + 1,
				mappedStatement.getId().length());
		for (Method method : classType.getDeclaredMethods()) {
			if (method.isAnnotationPresent(SqlChange.class) && methodName.equals(method.getName())) {
				// 可以获取改注解类型。
				SqlChange interceptorAnnotation = method.getAnnotation(SqlChange.class);

				// 修改sql
				sql = sql + " and name = '1'";
				System.out.println("修改后的 sql:" + sql);
			}
		}

		// 修改最终执行的sql语句
		Field field = boundSql.getClass().getDeclaredField("sql");
		field.setAccessible(true);
		field.set(boundSql, sql);

		return invocation.proceed();
	}

	@Override
	public Object plugin(Object target) {
		// 返回插件封装
		if (target instanceof StatementHandler) {
			return Plugin.wrap(target, this);
		} else {
			return target;
		}

	}

	@Override
	public void setProperties(Properties properties) {
		// 不会被调用
		System.out.println(properties);
	}

}
